perm filename NEWIO.F80[206,LSP] blob
sn#550370 filedate 1980-10-09 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00008 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 .s(IO,INPUT AND OUTPUT)
C00004 00003 .ss(basicio, Basic I/O operations.)
C00010 00004 .ss(files,Files)
C00032 00005 .ss(generalio, Basic I/O Operations Revisited.)
C00040 00006 .ss(ioex, I/O Examples.)
C00041 00007 .bb Elementary examples of file manipulation.
C00045 00008 .bb |The programs $PPOUT, $DSKIN and $$QREAD$.|
C00049 ENDMK
C⊗;
.s(IO,INPUT AND OUTPUT)
There are three components to Input and Output in MACLISP. First
are the basic functions which read and print.
Some of these deal with S-expressions, others with characters.
There are also functions to do conversions between characters and ASCII code.
Second there is a collection of switches which can be turned on or
off to control the source of input and the destinations of output. Typically
the input source is either the terminal or the currently opened file.
Output can go to the terminal, some subset of the currently opened files, or both.
Finally there are the functions that open and close files.
.ss(basicio, Basic I/O operations.)
We begin with a description of the I/O operations
on the user's terminal. The same operations can be used for doing "file"
I/O as will be explained later.
.begin indent 0,4
$(READ) reads one S-expression, which is either a list enclosed in matching
parentheses or an atom delimited by a special character such as a
space or a parenthesis. (A parenthesis would be saved up and used on
the next call to $READ.) $READ returns the S-expression which it read,
converting it from the external representation as characters to LISP
internal form. When reading from a file, providing an argument to $READ
causes it to return the value of that argument when the end-of-file
is reached (unless you have specified a fancy eof function).
If no argument is provided, it closes the file and patiently waits for input
from the terminal.
$(READCH) like read, but reads in one character and returns it as a
character object.
$(TYI) reads in one character and returns a number which is the
ASCII code for the character.
$(PRINT_x) prints out the S-expression $x in a form which is readable
by humans but which could also be read back into LISP if it were
printed to a file rather than to the terminal.
The expression printed out is preceded by a newline and followed by
a space. If special characters or strings of characters are used with
other than their normal
meanings, for example if a parenthesis appears in the pname of an
atom, they are preceded and followed by "|" so that the output could be read
back in.
$(PRIN1_x) is the same as $(PRINT_x) except that the leading newline
and trailing space are omitted. $PRIN1 can be used to print multiple
items on a line, but spacing between the items must be provided for
explicitly, for example by evaluating $$(TYO 40)$.
$(PRINC_x) is like $(PRIN1_x) except that special characters or
strings of characters are not surrounded by "|".
This makes the output more
pleasing in certain situations, however it cannot be read back into
LISP.
$(TERPRI) types out a newline.
$(TYO_n) outputs a character whose ASCII code is given by the number $n.
$PRINC may also be used to output character objects.
.end
As an example of how some of these reading and printing functions
can be used here is part of a program that is used as a self-documentation
feature in a larger system. When the system is loaded it prints a message
telling the user to type $(BBHELP) for information. $BBHELP prints out
a message explaining itself then does a $READ. If the user then
types one of the topic names the appropriate message is printed otherwise
an error message is printed. The "|"s around each line of the message
tell LISP that this is really a single atom. $PRINC prints it as a
character string omitting the "|" delimeters. $PRINT would retain the "|"s.
.begin nofill
.select 6
(DEFUN BBHELP ()
(PROG (TOPIC)
(BBMSG)
HELP
(SETQ TOPIC (READ))
(COND ((EQ TOPIC 'HELP) (BBHELPER))
((EQ TOPIC 'SYNTAX) (BBSYNHELPER))
((EQ TOPIC 'PUB) (BBPUBHELPER))
((EQ TOPIC 'LPT) (BBLPTHELPER))
((EQ TOPIC 'TXT) (BBTXTHELPER))
((EQ TOPIC 'EXIT) (RETURN 'Bye))
(T (BBERRHELPER TOPIC)))
(GO HELP)))
(DEFUN BBMSG ()
(TERPRI)
(PRINC '|The BB programs convert a list of atoms having |)
(TERPRI)
(PRINC '|EXPR FEXPR or VALUE properties to an external form.|)
(TERPRI)
(PRINC '|Type HELP to get a list of BBHELP topics|)
(TERPRI)
(PRINC '|Type EXIT to get out of BBHELP|)
(TERPRI))
.end
.ss(files,Files)
I/O in LISP consists of communication between the LISP environment and
files located in the external world. LISP refers to these files by using
"file objects," which are special objects within the LISP environment
which serve as representatives of, or symbols for, the files in the
external world. Because there is a one-to-one correspondence between
files and file objects, it is often convenient to confuse the two and call
them both "file."
The LISP system includes functions which can manipulate files in
various ways: A file may be "opened," that is a file object may be
created and associated with a named file in the external world. A file
may be "closed," that is the association between the file-object and the
external file may be broken and the file-object deleted. The
file-accessing information contained in a file-object may be examined or
changed; for example, the line length of an output file may be adjusted.
The characters of information in the external file may be read or written.
The attributes of the external file, such as its name, may be changed.
.bb File names and other information.
In order to "open" a file, the external file and the file object
must be named so that a connection may be established between them. The
problem of naming file objects is solved trivially by making the rule that
whenever a file object is created its name is decided by the system and
returned as the value of the function that created it. File objects are
then referred to in the same way as any S-expression. Note that the name
of a file object does not have a printable form, so that if you want to
manipulate the file object by typing from the terminal (rather than from a
program), you must keep the file object as the value of an atomic symbol.
The naming of files in the outside world is more difficult because
MACLISP has to operate with several different outside worlds, that is,
under several different operating systems. Two forms for file names have
been defined, and functions are provided to make the
implementation-dependent translation from one form to the other. The
forms of a file name are called the namelist and the namestring.
The namestring is the implementation dependent form. Namestrings
are represented as LISP character strings, however atomic symbols may also
be used, in which case the pname of the atomic symbol is used as the
character string. The contents of a namestring is just a sequence of
characters which have meaning to the user and to the function "namelist,"
which converts a namestring to a namelist. Namestrings should be read in
using $READSTRING and printed out using $PRINC, so that no
quotes will appear around them.
A namelist is a list whose car somehow specifies the device and/or
directory which contains the file, and whose ⊗cdr specifies the name of the
file. The exact way in which the ⊗car specifies the device/directory is
implementation-dependent. It should not be of concern to programs. The
⊗cdr of a namelist is a list of names which are the components of the file
name if the operating system uses multi-component file names. Each name
is represented as an atomic symbol, which is "interned" so that it may be
tested using $EQ. An additional feature of namelists is the "star
convention," by which a namelist may contain unspecified components, which
are indicated by the atom *. The *'s are filled when needed using default
values that the system keeps on hand.
The conversion between namlists and namestrings are carried out
by the programs $NAMELIST and $NAMESTRING as follows:
.skip
.BEGIN INDENT 0,4 PREFACE 0
$NAMELIST (SUBR 1 arg) converts its argument to a namelist.
Omitted or * components in the argument produce *'s in the result.
$NAMESTRING (SUBR 1 arg) converts its argument from a namelist to a
namestring. It is the opposite of namelist.
.END
The functions $STATUS AND $SSTATUS examine and set the status
of system variables. Some of these maintain defualts for file I/O.
They are:
.skip
.begin indent 0,4 preface 0
$$(STATUS UDIR)$ returns the the name of the user's directory.
For example $$(DSK |S.SEK|)$. $SSTATUS does not apply.
$$(STATUS CRUNIT)$ returns the current (default) device and directory.
Is initialized to $$(STATUS UDIR)$ in LISP at LOTS (not in MACLISP).
$$(SSTATUS CRUNIT dev dir)$ sets the defaults for device and directory
to $dev and $dir respectively.
$$(STATUS CRFILE)$ returns the current (default) file name and extension.
It returns qNIL if none has been set.
$$(SSTATUS CRFILE nam ext)$ sets the defaults for file name and extiosion
to $nam and $ext respectively.
.end
An example may help clarify the connection between namelists and
namestrings. A file PS:<C.CS206>GAME.LSP would be referred to by the
namestring $|PS:<C.CS206>GAME.LSP.3| or by the namelist
$$((PS |C.CS206|) GAME LSP /3)$. If the first component of the namelist
is omitted then $CRUNIT is used. In some cases the file specification may
be omitted enitrely. The $CRUNIT and $CRFILE are used to make up a
specificaton.
Some additional information about file objects has been collected
here. It is in brief form and will be elaborated in later sections.
There is no way to input file objects to the reader, because they do not
have pnames or anything of that sort, but for convenience in error
messages and debugging the printer will print a file object as a sharp
sign (#), followed by the namestring of the external file to which the
file object is attached. # is the character which is used to indicate
that an object of unknown type is being printed. The information
contained within a file object is here described briefly.
.skip
.begin indent 0,4 preface 0
$NAMELIST the namelist for the external file of which the
file object is a representative.
$EOFFN a function which is applied when the end of an
input file is reached.
$ENDPAGEFN a function which is applied when the end of a page is
reached (on an output file.)
$LINEL the number of characters per line on an output file.
$Charpos the horizontal position on the line, where 0 is the left margin.
$CHRCT the number of character positions remaining on the current
line of an output file,
$PAGEL the number of lines per page.
$LINENUM the number of the current line, with 0 being the top of the page
$PAGENUM the number of the current page, with the first page being 0.
$FILEPOS the position within the file of the character
currently being accessed. (Not necessarily
meaningful for all kinds of files.)
.END
Note that as a special case $T is considered to be a file object which
represents the terminal.
.bb Opening and Closing Files
In order to do file input/output operations files must be opened
and closed. The LISP primitives $OPEN and $CLOSE carry out these tasks.
.begin indent 0,4
$OPEN (LSUBR 0 to 2 args) $$(OPEN <file> <mode>)$ opens a file and returns a
corresponding file object. The $<file> defaults to the
current default file. The $<mode> defaults to $NIL.
If $<file> is a namelist or namestring, a new file object
is created. If $<file> is a file object already, it is
closed and re-opened in the specified mode; its former
mode serve as the default for the $<mode>.
The $<mode> can be one of the following: $IN, $OUT, $APPEND
for input file, output file (creates a new file) and
output file (append to existing file), respectively.
[Remark: $<mode> can also be a list specifing attributes in addition to
"direction". These default to the right thing for ordinary input/output
in LISP.]
$CLOSE (SUBR 1 arg) $$(CLOSE x)$, where $x is a file, closes $x and returns $T.
If $x is already closed nothing happens, otherwise the file system is
directed to return $x to a quiescent state.
.end
.bb Specifying the Source or Destination for I/O.
When an I/O function is called, the source (file) from which it is
to take its input or the destinations (files) on which it is to put its
output may be specified directly as an argument to the function, or they
may be specified by default. The default input source and output
destinations are specified by several system variables, which may be
setq'ed or lambda-bound by the user. They are described below. $INFILE
is the default input source, if the switch $↑Q is $T. If $↑Q is $NIL the
terminal is used as the default input source. $OUTFILES is a list of
default output destinations. Output is sent to all of these files if the
$↑R switch is $T. Output also goes to the terminal unless the $↑W switch
is $T. Note that if the value of $INFILE is $T ($OUTFILES is qNIL
or $$(T)$) it means the terminal, any anything else must be a file object.
.skip
.begin indent 0,4 preface 0
$INFILE (VARIABLE) The value of $INFILE is a file object which is the
default input source if $↑Q is non-NIL. $INFILE can also be $T which
specifies that input will be from the terminal even if $↑Q is non-NIL.
The initial value of $INFILE is $T.
$↑Q (SWITCH) If the value of $↑Q is non-NIL, the default input source
is the value of the atom $INFILE. If $↑Q is $NIL, the default input source
is $NIL, i.e. the terminal.
$INSTACK (VARIABLE) The value of $INSTACK is a list of pushed-down values
of $INFILE. It is managed by the program $INPUSH. The initial value is qnil.
$OUTFILES (VARIABLE) The value of $OUTFILES is a list of file objects
which are output destinations if $↑R is not qNIL. Elements of the list
$OUTFILES may be either file objects created by $OPEN, or qNIL meaning
output to the terminal. Note that output goes to the terminal
anyway if $↑W is qNIL, so it is possible to get double characters
this way.
$↑R (SWITCH) If the value of $↑R is non-NIL, the default output
destinations include the files in the list which is the value of the atom
$OUTFILES.
$↑W (SWITCH) If the value of $↑W is non-NIL, the default output destinations
do not include the terminal. (Unless $↑R is on and $T is a member
of the outfiles list.)
$FILEPOS (LSUBR 1 or 2 args)
$$(FILEPOS x)$, where $x is a file object open for input, returns the
current character position within the file as a fixnum. The
beginning of the file is 0.
$$(FILEPOS x n)$, where $x is a file object open for input and $n is a
non-negative fixnum, resets the character position of the file to
position specified by $n. It is an error if this position does
not lie within the file or if the file is not randomly
accessible. $N is returned.
.end
.skip 2
.bb Handling End of File
Calls to the input functions $READ, $READCH, $READSTRING, and $TYI
specify an argument called the $eofval. If this argument is omitted qNIL
is assumed. If the end of the input file is reached during the execution
of the function, the $eofval argument is used by the following procedure:
Each file object has an end-of-file handler, its $eoffn. When an
end of file occurs while input is being taken from this file, the $eoffn
is examined. (Eof on the terminal cannot occur.) If the $eoffn is qNIL,
then the following default action is taken: If eofval on the call to
$READ was not supplied, then the input file is closed and $READ continues
taking characters from a new input file popped off the input stack. If
the input stack is empty, $$(SETQ ↑Q NIL)$ is done and read continues
reading from the terminal. If an $eofval was supplied on the call to
$READ, then $READ immediately returns it. The input file is not closed.
This is not strictly true in the case where the input function is
$READ or $READSTRING and it is in the middle of an object. In this case,
rather than allowing the object to cross files, a $fail-act error occurs.
The argument passed to the user interrupt service function is the list
$$(READ-EOF)$. If the interrupt service function returns an atom (such as
qNIL), $READ $errs out; but if it returns a list, $READ goes on reading
from the new input source as if there had not been any end-of-file.
If the $eoffn for the input file is not qNIL, then it is a
function and it is applied with two arguments. The first argument is the
file object that eof'ed. The second argument is the $eofval on the call
to $READ, or, if an $eofval was not supplied, qNIL. If the $eoffn returns
qNIL, the file is closed and reading continues from the input source
popped off the input stack. The above prohibition of objects crossing
$eofs applies. If the $eoffn returns qT, reading continues from whatever
input source was made the current default one by the $eoffn. If the
$eoffn returns something other than qT or qNIL, then $READ immediately
returns whatever the $eoffn returned, and the file is not closed unless
the $eoffn closes it.
.skip
.begin indent 0,4 preface 0
$EOFFN (LSUBR 1 OR 2 ARGS)
$$(EOFFN x)$, where $x is an input file, gets $$x$'s end-of-file
function. The end-of-file function is called if the end of the
file is reached during input.
$$(EOFFN qNIL)$ gets the default end-of-file function.
$$(EOFFN x f)$ sets $$x$'s end-of-file function to $f.
$$(EOFFN qNIL f)$ sets the default end-of-file function to $f.
$f may be qNIL, which means that no end-of-file function is to be used.
.end
.ss(generalio, Basic I/O Operations Revisited.)
.begin indent 0,4 preface 0
$READ (LSUBR 0 TO 2 ARGS)
$(READ) reads an S-expression from the default input source.
$$(READ f)$, where $f is a file or qNIL meaning the terminal, reads an
S-expression from $f. During the reading, $INFILE and $↑Q are bound
so that evaluation of $$(READ)$ within a macro-character function
will read from the correct input source.
$$(READ x)$, where $x is not a file and not qNIL, passes $x as an
argument to the end-of-file function of the input source if the
end of the file is reached. Usually this means that read will
return $x if there are no more S-expressions in the file.
$$(READ T)$ suppresses the calling of the end-of-file function if
the end of the file is reached. Instead, read just returns T.
$$(READ x f)$ or $$(READ f x)$ specifies the end-of-file value $x and
selects the input source $f.
$READCH (LSUBR 0 TO 2 ARGS)
$READCH reads in one character and returns a character object.
The arguments are the same as for read.
$READLINE (LSUBR 0 TO 2 ARGS)
$READLINE reads in a line of text, strips off the newline
character or characters at the end, and returns it in the form of
a character string. The arguments are the same as for $READ. The
main use for $READLINE is reading in file names typed by the user
at his terminal in response to a question.
$TYI (LSUBR 0 TO 2 ARGS)
$TYI inputs one character and returns a fixnum which is the ascii
code for that character. The arguments are the same as for $READ.
$TYIPEEK (LSUBR 0 OR 1 ARG)
$$(TYIPEEK)$ is like $(TYI) except that the character is not eaten;
it is still in the input stream where the next call to an input
operation will find it. Thus $$(EQ (TYIPEEK) (TYI))$ is $T. If the
end of the file is reached, $TYIPEEK returns 3, (the ascii code
for "end of text.") The end of file function is not called.
$$(TYIPEEK n)$, where $n is a fixnum < 200 octal, skips over
characters of input until one is reached with an ascii code of $n.
That character is not eaten.
$$(TYIPEEK n)$, where $n is a fixnum > 1000 octal, skips over
characters of input until one is reached whose syntax bits from
the readtable, logically anded with (lsh n -9.), are nonzero.
$$(TYIPEEK t)$ skips over characters of input until the beginning of
an S-expression is reached. Splicing macro characters, such as
";" comments, are not considered to begin an object. If one is
encountered, its associated function is called as usual (so that
the text of the comment can be gobbled up or whatever) and
$TYIPEEK continues scanning characters.
$PRIN1 (LSUBR 1 OR 2 ARGS)
$$(PRIN1 x)$ outputs $x to the current output destination(s), in a
form suitable for reading back in.
$$(PRIN1 x f)$ outputs $x on the file $f, or the terminal if $f is
qNIL.
$PRINT (LSUBR 1 OR 2 ARGS)
$PRINT is like $PRIN1 except that the output is preceded by a
newline and followed by a space. This is the output function
most often used.
$$(PRINT x)$ prints $x to the default output destinations.
$$(PRINT x f)$ prints $x to the file $f, or to the terminal if $f is
qNIL.
$PRINC (LSUBR 1 OR 2 ARGS)
$PRINC is like $PRIN1 except that special characters are not
slashified and strings are not quoted.
$$(PRINC x)$ outputs $x to the current output destination(s).
$$(PRINC x f)$ outputs $x to the file $f, or the terminal if $f is qNIL.
$TYO (LSUBR 1 OR 2 ARGS)
$(TYO n)$ types out the character whose ascii code is $n on the
current output destination(s).
$$(TYO n f)$ types out the character whoe ascii code is $n on the
file $f or on the terminal if $f is qNIL. $TYO returns its first
argument.
$TERPRI (LSUBR 0 OR 1 ARG)
$(TERPRI) sends a newline to the current output destination(s).
$$(TERPRI x)$ sends a newline to $x, where $x may be an output file or
qNIL meaning the terminal.
$INPUSH (SUBR 1 ARG)
$$(INPUSH x)$, where $x is a file object open for input or qNIL to
specify the terminal, pushes the current input source onto the
input stack and selects $x as the current input source.
$$(INPUSH 0)$ just returns $INFILE.
$$(INPUSH -1)$ pops a new input source off of the input stack:
In the case that $INSTACK is qNIL, i.e. empty. In this case $INPUSH
leaves $INSTACK qNIL and makes $INFILE $T, which means the terminal.
$$(INPUSH -n)$ does $$(INPUSH -1)$ $n times.
$$(INPUSH 1)$ does $$(INPUSH (INPUSH 0))$, $$(INPUSH +n)$ does that
$n times.
The value of $INPUSH is the newly selected input source. If
$INPUSH causes $INFILE to be set to $T, $↑Q is set to qNIL since the
terminal has become the input source.
.end
.NEXT PAGE
.ss(ioex, I/O Examples.)
.bb File selection
$TTYMSG is an example of how the file selection works.
$TTYMSG will write the message given to it
as an argument on the terminal no matter what the value of the I/O switches
are when it is called. It saves the current switches, disables output to
a file and enables output to the terminal, $$PRINT$s the message then
restores the switches.
.begin verbatim select 6
(DEFPROP TTYMSG
(LAMBDA(MSG)
(PROG (CR CW) (SETQ CR ↑R CW ↑W)
(SETQ ↑R NIL ↑W NIL)
(PRINT MSG)
(TERPRI)
(SETQ ↑R CR ↑W CW)))
EXPR)
.end
.bb Elementary examples of file manipulation.
.begin verbatim select 6
(defun readloop (fileob) for reading to end-of-file
(prog (form if)
(setq if (open fileob 'in))
loop (setq form (read if))
(print form)
(cond ((null form) (return if)))
(go loop)))
READLOOP
(setq of (open '(tmp 1) 'out)) ;;; open file called TMP.1 for output
#FILE-OUT-|DSK:DSK:<S.SEK>TMP.1.25}-64774 ;;; makes a new version
(print '|hello there| of) ;;; write a messge
T
(close of)
T
(readloop of) ;;; old version is not contained
|hello there| ;;; in new version
NIL
#FILE-IN-|DSK:<S.SEK>TMP.1|-64774
of
#FILE-IN-|DSK:<S.SEK>TMP.1|-64774 ;;;NB the file object has been changed!
(setq of (open of 'out))
#FILE-OUT-|DSK:DSK:<S.SEK>TMP.1.26|-64774
(close of)
T
(readloop of)
NIL ;;; nothing sent, nothing there
#FILE-IN-|DSK:<S.SEK>TMP.1|-64774
(setq of (open '(tmp 1) 'out)) ;;; start again
#FILE-OUT-|PS:<S.SEK>TMP.1.27|-64774
(print '|me again| of)
T
(close of)
T
(readloop of)
|me again|
NIL
#FILE-IN-|DSK:<S.SEK>TMP.1|-64774
(setq af (open of 'append))
#FILE-OUT-|PS:<S.SEK>TMP.1.28|-64774
(print '|whats new| af)
T
(close af)
T
(readloop of)
|me again|
|whats new|
NIL
#FILE-IN-|DSK:<S.SEK>TMP.1|-64774
;;; In append mode the original contents of the file should still be there.
;;; Currently APPEND mode just makes a new version. In Tenex-20 you can
;;; append the two versions yourself using the monitor command APPEND.
;;; Hopefully this bug will be fixed soon.
;;; In order to get output to a file must give file object to output
;;; program directly or turnon ↑R switch and put the intended file object(s)
;;; on the $OUTFILES list.
(setq of (open of 'out)
#FILE-OUT-|PS:<S.SEK>TMP.1.29|-64774
((lambda(↑r outfiles)(print '|setting ↑r and outfiles?|))t (list af))
|setting only ↑r and outfiles?|
T
(close af)
T
(readloop of)
|setting ↑r and outfiles?|
NIL
#FILE-IN-|DSK:<S.SEK>TMP.1|-64774
.end
.NEXT PAGE
.bb |The programs $PPOUT, $DSKIN and $$QREAD$.|
Here is the code for the programs $PPOUT, $DKSIN, and $QREAD
described in Section {section LOTS}.
.begin VERBATIM SELECT 6
(DEFUN PPOUT FEXPR (F)
((LAMBDA (LOADGRINDER OCRU OCRF OFILE ↑W ↑R)
(PROG (FNS)
(SETQ OUTFILES (LIST OFILE)) ;;;files to write to
(SETQ FNS (CDR F))
LOOP (COND ((NOT (NULL FNS))
(APPLY 'GRINDEF (LIST (CAR FNS)))
(SETQ FNS (CDR FNS))
(GO LOOP)))
(CLOSE OFILE)
(APPLY 'CRUNIT OCRU) ;;;restore file status
(APPLY 'SSTATUS (CONS 'CRFILE OCRF))
(SETQ OUTFILES NIL)
(RETURN OFILE)))
(COND ((NOT (GET 'GRINDEF 'FSUBR)) ;;;load grinder if not there
(APPLY 'LOAD
(LIST (GET 'GRINDEF 'AUTOLOAD)))))
(STATUS CRUNIT) ;;;save current file status
(STATUS CRFILE)
(OPEN (MAKE-FILE-SPECS (CAR F)) 'OUT)
T ;;;turnoff tty
T)) ;;;turnon dsk
(DEFUN QREAD FEXPR (F)
((LAMBDA (OCRU OCRF IFILE)
(PROG (FORM)
LOOP (SETQ FORM (READ IFILE))
(COND (FORM (EVAL FORM) (GO LOOP)))
(APPLY 'CRUNIT OCRU)
(APPLY 'SSTATUS (CONS 'CRFILE OCRF))
(INPUSH -1)
(RETURN IFILE)))
(STATUS CRUNIT)
(STATUS CRFILE)
(INPUSH (OPEN (MAKE-FILE-SPECS F) 'IN))))
(DEFUN DSKIN FEXPR (F)
((LAMBDA (OCRU OCRF IFILE)
(PROG (FORM)
LOOP (SETQ FORM (READ IFILE))
(COND (FORM (PRINT (EVAL FORM)) (GO LOOP)))
(TERPRI)
(APPLY 'CRUNIT OCRU)
(APPLY 'SSTATUS
(CONS 'CRFILE OCRF))
(INPUSH -1)
(RETURN IFILE)))
(STATUS CRUNIT)
(STATUS CRFILE)
(INPUSH(OPEN (MAKE-FILE-SPECS F) 'IN))))
(DEFUN MAKE-FILE-SPECS (F) (COND ((ATOM (CAR F)) (CONS (CRUNIT) F)) (T F)))
.END